/*
    poparser  Copyright (C) 2023  Zhai YongNing <zhaiyn-free@foxmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>
*/
#include <getopt.h>
#include <initializer_list>
#include <iostream>
#include <map>
#include <string>
#include <vector>
class POParser
{
private:
  bool parser_be_init = false;
  const std::vector<std::string> null_v;
  std::map<std::string, std::vector<std::string> > optargs;
  std::map<std::string,
           std::tuple<bool /* need_more_arg*/, bool /*optional_arg*/,
                      int * /*variable*/, int /*value*/,
                      bool (*) (std::vector<std::string> &) /*func*/> >
      options_map;
  struct ::option *long_options = nullptr;
  std::string short_options;
  void __copy (const POParser &p);
  void __move (POParser &&);

public:
  enum class NumOfArg
  {
    No,
    Optional,
    Has
  };
  POParser (); // 默认初始化，不初始化分析器
  POParser &operator= (const POParser &p); // 拷贝赋值
  POParser (const POParser &);             // 拷贝初始化
  POParser &operator= (POParser &&p);      // 移动赋值
  POParser (POParser &&);                  // 移动初始化
  /*
  列表初始化，是主要的初始化，同时完成分析器的初始化，是唯一的分析器初始化方式
  列表中每一项，描述一组选项的名称及其行为，包括一个或零个短选项，零个或多个长选项，
  同一组中的短选项及所有长选项的行为是一致的：
  1：字符串常量，第一个字符有效，指定程序命令行的短选项，如不使用短选项，设为空字符串；
  2：常量字符串向量组，指明与短选项等效的所有长选项，每一个向量对应一个长选项；
  3：选项是否拥有参数，No 表示无，Has 表示必须有，Optional 表示有或无；
  4：选项是否拥有扩展参数，即超过一个的参数；
  5：选项对应的变量的地址，在程序命令行中出现该选项时，该变量的值被改变；
  6：选项对应变量改变的值；
  7：选项对应的钩子函数；在程序命令行中出现该选项时，该函数被调用；
  */
  POParser (const std::initializer_list<
            const std::tuple<const char *, const std::vector<const char *>,
                             const NumOfArg, const bool, int *const, const int,
                             bool (*) (std::vector<std::string> &)> > &);
/*
  分析命令行参数；
  入口参数: 1. argc 命令行参数的数量，也就是main()函数的第一个参数。
           2. argv  命令行参数数组，也就是main()函数的第二个参数。
  返回值：正常，返回true
*/
  bool parse (const int argc, char **argv, bool append = false);

  operator bool () const; // 返回值表示分析器是否有被分析出的选项及参数
/*
  获得程序命令行中，命令行选项对应的选项参数。
  入口参数：std::string,表示选项；短选项前加'-',长选项前加'--'；如果长选项存在对应的短选项，则无法
           使用长选项；
  返回值：std::vector<std::string>的引用；每个string对应一个选项参数；如果vector为空，表明该选项
         在命令行中没有出现，如果vector的第一个string为空,表示命令行中出现了该选项，但没有参数出现。
*/
  const decltype (POParser::optargs)::mapped_type &
  operator[] (const std::string) const;
/*
  等效增加一个命令行选项及对应的选项参数。
  入口参数：1. std::string,表示选项；短选项前加'-',长选项前加'--'；如果长选项存在对应的短选项，则
              无法使用长选项；
           2. std::string,表示参数；默认为空；
  返回值：std::vector<std::string>的引用；每个string对应一个选项参数；如果vector为空，表明该选项
         在命令行中没有出现，如果vector的第一个string为空,表示命令行中出现了该选项，但没有参数出现。
*/
  const decltype (POParser::optargs)::mapped_type &append (
      const std::string, const std::string & = std::string (""));
/*
  删除一个命令行选项对应的选项参数，等效命令行中不存在该选项及参数；
  入口参数：std::string,表示选项；短选项前加'-',长选项前加'--'；如果长选项存在对应的短选项，则无法
           使用长选项；
  返回值：正常返回true,否则返回false;
*/
  bool remove (const std::string);

// 提取分析后的所有结果(选项及其参数），并输出到流
  friend std::ostream &operator<< (std::ostream &, const POParser &);
  ~POParser ();
};